home *** CD-ROM | disk | FTP | other *** search
/ Clickx 96 / Clickx 96.iso / software / tools / tool / xbmc-10.1.exe / addons / script.module.pil / lib / PIL / ArgImagePlugin.py < prev    next >
Encoding:
Python Source  |  2009-04-06  |  12.1 KB  |  505 lines

  1. #
  2. # THIS IS WORK IN PROGRESS
  3. #
  4. # The Python Imaging Library.
  5. # $Id$
  6. #
  7. # ARG animation support code
  8. #
  9. # history:
  10. # 1996-12-30 fl   Created
  11. # 1996-01-06 fl   Added safe scripting environment
  12. # 1996-01-10 fl   Added JHDR, UHDR and sYNC support
  13. # 2005-03-02 fl   Removed AAPP and ARUN support
  14. #
  15. # Copyright (c) Secret Labs AB 1997.
  16. # Copyright (c) Fredrik Lundh 1996-97.
  17. #
  18. # See the README file for information on usage and redistribution.
  19. #
  20.  
  21. __version__ = "0.4"
  22.  
  23. import Image, ImageFile, ImagePalette
  24.  
  25. from PngImagePlugin import i16, i32, ChunkStream, _MODES
  26.  
  27. MAGIC = "\212ARG\r\n\032\n"
  28.  
  29. # --------------------------------------------------------------------
  30. # ARG parser
  31.  
  32. class ArgStream(ChunkStream):
  33.     "Parser callbacks for ARG data"
  34.  
  35.     def __init__(self, fp):
  36.  
  37.         ChunkStream.__init__(self, fp)
  38.  
  39.         self.eof = 0
  40.  
  41.         self.im = None
  42.         self.palette = None
  43.  
  44.         self.__reset()
  45.  
  46.     def __reset(self):
  47.  
  48.         # reset decoder state (called on init and sync)
  49.  
  50.         self.count = 0
  51.         self.id = None
  52.         self.action = ("NONE",)
  53.  
  54.         self.images = {}
  55.         self.names = {}
  56.  
  57.  
  58.     def chunk_AHDR(self, offset, bytes):
  59.         "AHDR -- animation header"
  60.  
  61.         # assertions
  62.         if self.count != 0:
  63.             raise SyntaxError, "misplaced AHDR chunk"
  64.  
  65.         s = self.fp.read(bytes)
  66.         self.size = i32(s), i32(s[4:])
  67.         try:
  68.             self.mode, self.rawmode = _MODES[(ord(s[8]), ord(s[9]))]
  69.         except:
  70.             raise SyntaxError, "unknown ARG mode"
  71.  
  72.         if Image.DEBUG:
  73.             print "AHDR size", self.size
  74.             print "AHDR mode", self.mode, self.rawmode
  75.  
  76.         return s
  77.  
  78.     def chunk_AFRM(self, offset, bytes):
  79.         "AFRM -- next frame follows"
  80.  
  81.         # assertions
  82.         if self.count != 0:
  83.             raise SyntaxError, "misplaced AFRM chunk"
  84.  
  85.         self.show = 1
  86.         self.id = 0
  87.         self.count = 1
  88.         self.repair = None
  89.  
  90.         s = self.fp.read(bytes)
  91.         if len(s) >= 2:
  92.             self.id = i16(s)
  93.             if len(s) >= 4:
  94.                 self.count = i16(s[2:4])
  95.                 if len(s) >= 6:
  96.                     self.repair = i16(s[4:6])
  97.                 else:
  98.                     self.repair = None
  99.  
  100.         if Image.DEBUG:
  101.             print "AFRM", self.id, self.count
  102.  
  103.         return s
  104.  
  105.     def chunk_ADEF(self, offset, bytes):
  106.         "ADEF -- store image"
  107.  
  108.         # assertions
  109.         if self.count != 0:
  110.             raise SyntaxError, "misplaced ADEF chunk"
  111.  
  112.         self.show = 0
  113.         self.id = 0
  114.         self.count = 1
  115.         self.repair = None
  116.  
  117.         s = self.fp.read(bytes)
  118.         if len(s) >= 2:
  119.             self.id = i16(s)
  120.             if len(s) >= 4:
  121.                 self.count = i16(s[2:4])
  122.  
  123.         if Image.DEBUG:
  124.             print "ADEF", self.id, self.count
  125.  
  126.         return s
  127.  
  128.     def chunk_NAME(self, offset, bytes):
  129.         "NAME -- name the current image"
  130.  
  131.         # assertions
  132.         if self.count == 0:
  133.             raise SyntaxError, "misplaced NAME chunk"
  134.  
  135.         name = self.fp.read(bytes)
  136.         self.names[self.id] = name
  137.  
  138.         return name
  139.  
  140.     def chunk_AEND(self, offset, bytes):
  141.         "AEND -- end of animation"
  142.  
  143.         if Image.DEBUG:
  144.             print "AEND"
  145.  
  146.         self.eof = 1
  147.  
  148.         raise EOFError, "end of ARG file"
  149.  
  150.     def __getmodesize(self, s, full=1):
  151.  
  152.         size = i32(s), i32(s[4:])
  153.  
  154.         try:
  155.             mode, rawmode = _MODES[(ord(s[8]), ord(s[9]))]
  156.         except:
  157.             raise SyntaxError, "unknown image mode"
  158.  
  159.         if full:
  160.             if ord(s[12]):
  161.                 pass # interlace not yet supported
  162.             if ord(s[11]):
  163.                 raise SyntaxError, "unknown filter category"
  164.  
  165.         return size, mode, rawmode
  166.  
  167.     def chunk_PAST(self, offset, bytes):
  168.         "PAST -- paste one image into another"
  169.  
  170.         # assertions
  171.         if self.count == 0:
  172.             raise SyntaxError, "misplaced PAST chunk"
  173.  
  174.         if self.repair is not None:
  175.             # we must repair the target image before we
  176.             # start pasting
  177.  
  178.             # brute force; a better solution would be to
  179.             # update only the dirty rectangles in images[id].
  180.             # note that if images[id] doesn't exist, it must
  181.             # be created
  182.  
  183.             self.images[self.id] = self.images[self.repair].copy()
  184.             self.repair = None
  185.  
  186.         s = self.fp.read(bytes)
  187.         im = self.images[i16(s)]
  188.         x, y = i32(s[2:6]), i32(s[6:10])
  189.         bbox = x, y, im.size[0]+x, im.size[1]+y
  190.  
  191.         if im.mode in ["RGBA"]:
  192.             # paste with transparency
  193.             # FIXME: should handle P+transparency as well
  194.             self.images[self.id].paste(im, bbox, im)
  195.         else:
  196.             # paste without transparency
  197.             self.images[self.id].paste(im, bbox)
  198.  
  199.         self.action = ("PAST",)
  200.         self.__store()
  201.  
  202.         return s
  203.  
  204.     def chunk_BLNK(self, offset, bytes):
  205.         "BLNK -- create blank image"
  206.  
  207.         # assertions
  208.         if self.count == 0:
  209.             raise SyntaxError, "misplaced BLNK chunk"
  210.  
  211.         s = self.fp.read(bytes)
  212.         size, mode, rawmode = self.__getmodesize(s, 0)
  213.  
  214.         # store image (FIXME: handle colour)
  215.         self.action = ("BLNK",)
  216.         self.im = Image.core.fill(mode, size, 0)
  217.         self.__store()
  218.  
  219.         return s
  220.  
  221.     def chunk_IHDR(self, offset, bytes):
  222.         "IHDR -- full image follows"
  223.  
  224.         # assertions
  225.         if self.count == 0:
  226.             raise SyntaxError, "misplaced IHDR chunk"
  227.  
  228.         # image header
  229.         s = self.fp.read(bytes)
  230.         size, mode, rawmode = self.__getmodesize(s)
  231.  
  232.         # decode and store image
  233.         self.action = ("IHDR",)
  234.         self.im = Image.core.new(mode, size)
  235.         self.decoder = Image.core.zip_decoder(rawmode)
  236.         self.decoder.setimage(self.im, (0,0) + size)
  237.         self.data = ""
  238.  
  239.         return s
  240.  
  241.     def chunk_DHDR(self, offset, bytes):
  242.         "DHDR -- delta image follows"
  243.  
  244.         # assertions
  245.         if self.count == 0:
  246.             raise SyntaxError, "misplaced DHDR chunk"
  247.  
  248.         s = self.fp.read(bytes)
  249.  
  250.         size, mode, rawmode = self.__getmodesize(s)
  251.  
  252.         # delta header
  253.         diff = ord(s[13])
  254.         offs = i32(s[14:18]), i32(s[18:22])
  255.  
  256.         bbox = offs + (offs[0]+size[0], offs[1]+size[1])
  257.  
  258.         if Image.DEBUG:
  259.             print "DHDR", diff, bbox
  260.  
  261.         # FIXME: decode and apply image
  262.         self.action = ("DHDR", diff, bbox)
  263.  
  264.         # setup decoder
  265.         self.im = Image.core.new(mode, size)
  266.  
  267.         self.decoder = Image.core.zip_decoder(rawmode)
  268.         self.decoder.setimage(self.im, (0,0) + size)
  269.  
  270.         self.data = ""
  271.  
  272.         return s
  273.  
  274.     def chunk_JHDR(self, offset, bytes):
  275.         "JHDR -- JPEG image follows"
  276.  
  277.         # assertions
  278.         if self.count == 0:
  279.             raise SyntaxError, "misplaced JHDR chunk"
  280.  
  281.         # image header
  282.         s = self.fp.read(bytes)
  283.         size, mode, rawmode = self.__getmodesize(s, 0)
  284.  
  285.         # decode and store image
  286.         self.action = ("JHDR",)
  287.         self.im = Image.core.new(mode, size)
  288.         self.decoder = Image.core.jpeg_decoder(rawmode)
  289.         self.decoder.setimage(self.im, (0,0) + size)
  290.         self.data = ""
  291.  
  292.         return s
  293.  
  294.     def chunk_UHDR(self, offset, bytes):
  295.         "UHDR -- uncompressed image data follows (EXPERIMENTAL)"
  296.  
  297.         # assertions
  298.         if self.count == 0:
  299.             raise SyntaxError, "misplaced UHDR chunk"
  300.  
  301.         # image header
  302.         s = self.fp.read(bytes)
  303.         size, mode, rawmode = self.__getmodesize(s, 0)
  304.  
  305.         # decode and store image
  306.         self.action = ("UHDR",)
  307.         self.im = Image.core.new(mode, size)
  308.         self.decoder = Image.core.raw_decoder(rawmode)
  309.         self.decoder.setimage(self.im, (0,0) + size)
  310.         self.data = ""
  311.  
  312.         return s
  313.  
  314.     def chunk_IDAT(self, offset, bytes):
  315.         "IDAT -- image data block"
  316.  
  317.         # pass compressed chunks through the decoder
  318.         s = self.fp.read(bytes)
  319.         self.data = self.data + s
  320.         n, e = self.decoder.decode(self.data)
  321.         if n < 0:
  322.             # end of image
  323.             if e < 0:
  324.                 raise IOError, "decoder error %d" % e
  325.         else:
  326.             self.data = self.data[n:]
  327.  
  328.         return s
  329.  
  330.     def chunk_DEND(self, offset, bytes):
  331.         return self.chunk_IEND(offset, bytes)
  332.  
  333.     def chunk_JEND(self, offset, bytes):
  334.         return self.chunk_IEND(offset, bytes)
  335.  
  336.     def chunk_UEND(self, offset, bytes):
  337.         return self.chunk_IEND(offset, bytes)
  338.  
  339.     def chunk_IEND(self, offset, bytes):
  340.         "IEND -- end of image"
  341.  
  342.         # we now have a new image.  carry out the operation
  343.         # defined by the image header.
  344.  
  345.         # won't need these anymore
  346.         del self.decoder
  347.         del self.data
  348.  
  349.         self.__store()
  350.  
  351.         return self.fp.read(bytes)
  352.  
  353.     def __store(self):
  354.  
  355.         # apply operation
  356.         cid = self.action[0]
  357.  
  358.         if cid in ["BLNK", "IHDR", "JHDR", "UHDR"]:
  359.             # store
  360.             self.images[self.id] = self.im
  361.  
  362.         elif cid == "DHDR":
  363.             # paste
  364.             cid, mode, bbox = self.action
  365.             im0 = self.images[self.id]
  366.             im1 = self.im
  367.             if mode == 0:
  368.                 im1 = im1.chop_add_modulo(im0.crop(bbox))
  369.             im0.paste(im1, bbox)
  370.  
  371.         self.count = self.count - 1
  372.  
  373.         if self.count == 0 and self.show:
  374.             self.im = self.images[self.id]
  375.             raise EOFError # end of this frame
  376.  
  377.     def chunk_PLTE(self, offset, bytes):
  378.         "PLTE -- palette data"
  379.  
  380.         s = self.fp.read(bytes)
  381.         if self.mode == "P":
  382.             self.palette = ImagePalette.raw("RGB", s)
  383.         return s
  384.  
  385.     def chunk_sYNC(self, offset, bytes):
  386.         "SYNC -- reset decoder"
  387.  
  388.         if self.count != 0:
  389.             raise SyntaxError, "misplaced sYNC chunk"
  390.  
  391.         s = self.fp.read(bytes)
  392.         self.__reset()
  393.         return s
  394.  
  395.  
  396. # --------------------------------------------------------------------
  397. # ARG reader
  398.  
  399. def _accept(prefix):
  400.     return prefix[:8] == MAGIC
  401.  
  402. ##
  403. # Image plugin for the experimental Animated Raster Graphics format.
  404.  
  405. class ArgImageFile(ImageFile.ImageFile):
  406.  
  407.     format = "ARG"
  408.     format_description = "Animated raster graphics"
  409.  
  410.     def _open(self):
  411.  
  412.         if Image.warnings:
  413.             Image.warnings.warn(
  414.                 "The ArgImagePlugin driver is obsolete, and will be removed "
  415.                 "from a future release of PIL.  If you rely on this module, "
  416.                 "please contact the PIL authors.",
  417.                 RuntimeWarning
  418.                 )
  419.  
  420.         if self.fp.read(8) != MAGIC:
  421.             raise SyntaxError, "not an ARG file"
  422.  
  423.         self.arg = ArgStream(self.fp)
  424.  
  425.         # read and process the first chunk (AHDR)
  426.  
  427.         cid, offset, bytes = self.arg.read()
  428.  
  429.         if cid != "AHDR":
  430.             raise SyntaxError, "expected an AHDR chunk"
  431.  
  432.         s = self.arg.call(cid, offset, bytes)
  433.  
  434.         self.arg.crc(cid, s)
  435.  
  436.         # image characteristics
  437.         self.mode = self.arg.mode
  438.         self.size = self.arg.size
  439.  
  440.     def load(self):
  441.  
  442.         if self.arg.im is None:
  443.             self.seek(0)
  444.  
  445.         # image data
  446.         self.im = self.arg.im
  447.         self.palette = self.arg.palette
  448.  
  449.         # set things up for further processing
  450.         Image.Image.load(self)
  451.  
  452.     def seek(self, frame):
  453.  
  454.         if self.arg.eof:
  455.             raise EOFError, "end of animation"
  456.  
  457.         self.fp = self.arg.fp
  458.  
  459.         while 1:
  460.  
  461.             #
  462.             # process chunks
  463.  
  464.             cid, offset, bytes = self.arg.read()
  465.  
  466.             if self.arg.eof:
  467.                 raise EOFError, "end of animation"
  468.  
  469.             try:
  470.                 s = self.arg.call(cid, offset, bytes)
  471.             except EOFError:
  472.                 break
  473.  
  474.             except "glurk": # AttributeError
  475.                 if Image.DEBUG:
  476.                     print cid, bytes, "(unknown)"
  477.                 s = self.fp.read(bytes)
  478.  
  479.             self.arg.crc(cid, s)
  480.  
  481.         self.fp.read(4) # ship extra CRC
  482.  
  483.     def tell(self):
  484.         return 0
  485.  
  486.     def verify(self):
  487.         "Verify ARG file"
  488.  
  489.         # back up to first chunk
  490.         self.fp.seek(8)
  491.  
  492.         self.arg.verify(self)
  493.         self.arg.close()
  494.  
  495.         self.fp = None
  496.  
  497. #
  498. # --------------------------------------------------------------------
  499.  
  500. Image.register_open("ARG", ArgImageFile, _accept)
  501.  
  502. Image.register_extension("ARG", ".arg")
  503.  
  504. Image.register_mime("ARG", "video/x-arg")
  505.